package org.zhongyin.Forcast;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jxl.read.biff.BiffException;

import org.apache.commons.math3.exception.NullArgumentException;
import org.joda.time.DateTime;
import org.zhongyin.Dao.LocalDBDaoImpl;
import org.zhongyin.Regression.Regression;
import org.zhongyin.Util.Utility;
import org.zhongyin.core.IARXModel;
import org.zhongyin.internal.core.ARXFirstWDProvider;
import org.zhongyin.internal.core.ARXFirstWEProvider;
import org.zhongyin.internal.core.ARXSecondWDProvider;

import Jama.Matrix;

public class Forcasting {

	public Forcasting() throws IOException, ParseException, BiffException {

	}

	private Matrix calculateCofficient(IARXModel test){
		
		double[][] array_X = test.getARXmodel_X();

		double[] array_Y = test.getARXmodel_Y();

		// Utility.printArraySingleLine(test.getARXmodel_X());
		//
		// System.out.println(Arrays.toString(test.getARXmodel_Y()));
		int length = array_Y.length;

		Matrix weight = Matrix.identity(length, length);

		Regression regression = new Regression();

		weight = regression.getIterWeight(array_Y, array_X, weight);

		// Utility.printArraySingleLine(weight.getArray());
		

		Matrix cofficient = regression.getWeightedCoefficient(array_Y,
				array_X, weight);
		return cofficient;
		
	}

	//
	public List<double[]> getNext6HoursData() throws BiffException, ParseException,
			IOException {
		DateTime now = new DateTime();
		ARXFirstWEProvider forcastWE = new ARXFirstWEProvider();
		forcastWE.setForcastData();

		ARXFirstWDProvider forcastWD = new ARXFirstWDProvider();
		forcastWD.setForcastData();
		
		List<double[]> result = new ArrayList<double[]>();
		// forcast next 6 hours
		for (int i = 1; i < 7; i++) {
			DateTime nexthours = now.plusHours(i);
			//Next hour is Saturday
			if (nexthours.getDayOfWeek() == 6) {

				forcastWE.setARXForcastmodel(i);
				double[][] forcast_x = forcastWE.getARXmodel_X();
				double[] arrCopy = Utility.copyArray(forcast_x, i-1, i);
//				Utility.printArray(forcast_x, i - 1, i);
				result.add(arrCopy);
				//Next hour is regular working day
			} else if (nexthours.getDayOfWeek() >= 1
					&& nexthours.getDayOfWeek() <= 5) {

				forcastWD.setARXForcastmodel(i);
				double[][] forcast_x = forcastWD.getARXmodel_X();
				double[] arrCopy = Utility.copyArray(forcast_x, i-1, i);
				
//				Utility.printArray(forcast_x, i - 1, i);
				result.add(arrCopy);
			}
		}
		
		return result;
	}
	
	

	/**
	 * Insert cofficient into database according to the latest data There are 7
	 * ARXModels ARX(1,2,24), ARX(2,3,24), ARX(3,4,24), ARX(4,5,24), ARX(5,6,24)
	 * and ARX(24,168)
	 * 
	 * @throws ParseException
	 * @throws BiffException
	 * @throws IOException
	 */
	public void insertCofficient(int hour) throws ParseException, BiffException,
			IOException {
		LocalDBDaoImpl l = new LocalDBDaoImpl();

		DateTime now = new DateTime();
		
		if (now.getDayOfWeek() >= 1 && now.getDayOfWeek() <= 5) {
			IARXModel test = new ARXFirstWDProvider();
			test.setHistdata();
			for (int i = 1; i <= 6; i++) {
				
				((ARXFirstWDProvider) test).setARXHistmodel(i, hour);

				Matrix cofficient = calculateCofficient(test);

				l.em.getTransaction().begin();

				l.addRunData(i);

				for (int j = 0; j < cofficient.getArray().length; j++) {

					l.addResultData(i, j, cofficient.get(j, 0),hour);

				}

				l.em.flush();
				l.em.getTransaction().commit();

				System.out.println("ARXModel(" + i + "," + (i + 1)
						+ ", 24) b: "
						+ Arrays.deepToString(cofficient.getArray()));
			}

			IARXModel second = new ARXSecondWDProvider();

			second.setHistdata();

			((ARXSecondWDProvider) second).setARXHistmodel(hour);
		
			Matrix cofficient = calculateCofficient(second);

			l.em.getTransaction().begin();

			l.addRunData(7);

			for (int j = 0; j < cofficient.getArray().length; j++) {

				l.addResultData(7, j, cofficient.get(j, 0), hour);

			}

			l.em.flush();
			l.em.getTransaction().commit();

			System.out.println("ARXModel(24, 168) b: "
					+ Arrays.deepToString(cofficient.getArray()));
		}
	}
	
	public double[] getCofficient(int typeId, int hour){
		LocalDBDaoImpl l = new LocalDBDaoImpl();
		List<Double> temp = l.getResult(typeId, hour);
		double[] result = new double[temp.size()];
		for(int i = 0 ; i < temp.size(); i++){
			result[i] = temp.get(i);
		}
		
		return result;
	}

	/**
	 * @param args
	 * @throws IOException
	 * @throws ParseException
	 * @throws BiffException
	 */
	public static void main(String[] args) throws IOException, BiffException,
			ParseException {

		Forcasting forcasting = new Forcasting();
		List<double[]> test = forcasting.getNext6HoursData();
		Utility.printArrayListDouble(test);
//		for(int i = 0; i <=23; i++){
//			forcasting.insertCofficient(i);
//		}
		DateTime date = new DateTime();
		int hour = date.getHourOfDay();
		
		
		forcasting.insertCofficient(hour);
		for(int i = 0; i < 6; i++){
			double[] array_b = forcasting.getCofficient(i+1, hour);
			Matrix X = new Matrix(test.get(i), test.get(i).length);
			Matrix b = new Matrix(array_b, array_b.length);
			Matrix Y = X.transpose().times(b);
			System.out.println(Y.get(0, 0));
		}

	}

}
